package edu.buaa.utils;

import cn.leancloud.LCObject;
import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.ListenableFuture;
import edu.buaa.common.client.MariaDbExecutorClient;
import edu.buaa.common.client.PostgreSqlExecutorClient;
import edu.buaa.common.transaction.AbstractTransaction;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DBSpaceStatistic {
    private static final String dbName = Helper.mustEnv("DATASET");
    private static final String dbType = Helper.mustEnv("DB_TYPE").toLowerCase();
    private static final String serverHost = Helper.mustEnv("DB_HOST"); // pg mariadb.
    private static final String serverPath = Helper.mustEnv("DB_PATH"); // tg neo4j
    private static final String tpRange = Helper.mustEnv("TP_RANGE");

    public static void main(String[] args) throws Exception {
        if(dbType.equals("mariadb")) {
            MariaDb cli = new MariaDb(serverHost, dbName);
            System.out.println(log(cli.currentStorageStatus()));
            cli.close();
        }else if(dbType.equals("postgresql")) {
            PostgreSQL pg = new PostgreSQL(serverHost, dbName);
            System.out.println(log(pg.currentStorageStatus()));
            pg.close();
        }else if(dbType.contains("neo4j")) {
            System.out.println(log(neo4jSize(new File(serverPath))));
        }else{
            System.out.println(log(tgraphSize(new File(serverPath))));
        }
    }

    private static String log(String json){
        Pattern pattern = Pattern.compile("(\\..+_\\d+-\\d+)");
        Matcher matcher = pattern.matcher(tpRange);
        LCObject testObject = new LCObject("TestMilestone");
        testObject.put("DB", dbType);
        testObject.put("Dataset", dbName);
        testObject.put("MSize", matcher.find()?matcher.group(0):"");
        testObject.put("detail", json);
        testObject.save();
        return json;
    }

    private static class MariaDb extends MariaDbExecutorClient{
        public MariaDb(String serverHost, String dbName) throws Exception {
            super(serverHost, dbName, 1);
        }
        @Override
        protected List<String> createTables() {
            return Collections.emptyList();
        }
        @Override
        public ListenableFuture<ServerResponse> execute(AbstractTransaction tx) throws Exception {
            throw new UnsupportedOperationException();
        }
    }

    private static class PostgreSQL extends PostgreSqlExecutorClient{
        public PostgreSQL(String serverHost, String dbName) throws Exception {
            super(serverHost, dbName, 1);
        }
        @Override
        public ListenableFuture<ServerResponse> execute(AbstractTransaction tx) throws Exception {
            throw new UnsupportedOperationException();
        }
        @Override
        protected List<String> createTables() {
            return Collections.emptyList();
        }
    }

    private static long size(final File file, FilenameFilter filter, int level) {
        if (file.isFile()) return file.length();
        final File[] children = file.listFiles(filter);
        long total = 0;
        if (children != null)
            for (final File child : children){
                StringBuilder sb = new StringBuilder();
                for(int i=0;i<level;i++) sb.append("|--");
                sb.append(child.getName()).append('\t').append(child.isFile()?child.length()+"":"");
                System.out.println(sb);
                total += size(child, filter, level+1);
            }
        return total;
    }

    private static long size(final File file, FilenameFilter filter) {
        System.out.println("------------------"+ file.getAbsolutePath()+"------------------");
        return size(file, filter, 0);
    }

    private static final FilenameFilter noFilter = (d, name) -> true;
    private static String neo4jSize(File dir){
        JSONObject obj = new JSONObject();
        long dbSize = size(dir, (d, name) -> !name.contains("messages.log") && !name.equalsIgnoreCase("schema"));
        long indexSize = size(new File(dir,"schema"), noFilter);
        obj.put("data", dbSize);
        obj.put("index", indexSize);
        return obj.toJSONString();
    }

    private static String tgraphSize(File path) {
        long neoData = size(path, (d, name) -> !name.contains("messages.log") && !name.equals("schema") && !name.startsWith("temporal"));
        long neoIndex = size(new File(path,"schema"), noFilter);
        long tpNodeData = size(new File(path,"temporal.node.properties"), (d, name) -> !name.equals("index"));
        long tpNodeIndex = size(new File(path, "temporal.node.properties/index"), noFilter);
        long tpRelData = size(new File(path,"temporal.relationship.properties"), (d, name) -> !name.equals("index"));
        long tpRelIndex = size(new File(path, "temporal.relationship.properties/index"), noFilter);
        JSONObject obj = new JSONObject();
        obj.put("neo_data", neoData);
        obj.put("neo_index", neoIndex);
        obj.put("tp_node_data", tpNodeData);
        obj.put("tp_node_index", tpNodeIndex);
        obj.put("tp_rel_data", tpRelData);
        obj.put("tp_rel_index", tpRelIndex);
        return obj.toJSONString();
    }
}
